using System;
using System.Text;

namespace FP_Tree
{


	/// <summary>
	/// This is an abstract class indicating general methods 
	/// that an ordered itemset should have, and is designed for ordered itemsets where items are sorted
	/// by lexical order and no item can appear twice.
	/// </summary>
	public abstract class AbstractItemset
	{

		public AbstractItemset() : base()
		{
		}

		/// <summary>
		/// Get the support of this itemset </summary>
		/// <returns> the support of this itemset </returns>
        public abstract int AbsoluteSupport();
      
		/// <summary>
		/// Get the size of this itemset </summary>
		/// <returns> the size of this itemset </returns>
		public abstract int size();

		/// <summary>
		/// Get the item at a given position of this itemset </summary>
		/// <param name="position"> the position of the item to be returned </param>
		/// <returns> the item </returns>
		public abstract int get(int position);

		/// <summary>
		/// Get the last item. </summary>
		/// <returns> the last item. </returns>
		public int LastItem
		{
			get
			{
				return get(size() - 1);
			}
		}

		/// <summary>
		/// Get this itemset as a string </summary>
		/// <returns> a string representation of this itemset </returns>
		public override string ToString()
		{
			// use a string buffer for more efficiency
			StringBuilder r = new StringBuilder();
			// for each item, append it to the stringbuffer
			for (int i = 0; i < size(); i++)
			{
				r.Append(get(i));
				r.Append(' ');
			}
			return r.ToString(); // return the tring
		}

		/// <summary>
		/// print this itemset to System.out.
		/// </summary>
		public void print()
		{
			Console.Write(ToString());
		}

		/// <summary>
		/// Get the relative support of this itemset as a string </summary>
		/// <param name="nbObject">  the number of transactions in the database where this itemset was found </param>
		/// <returns> the relative support of the itemset as a string </returns>
		public string getRelativeSupportAsString(int nbObject)
		{
			// get the relative support
			double frequence = getRelativeSupport(nbObject);
			// convert it to a string with two decimals
			//DecimalFormat format = new DecimalFormat();
			//format.MinimumFractionDigits = 0;
			//format.MaximumFractionDigits = 5;
            return frequence+"";//format.format();
		}


		/// <summary>
		/// Get the relative support of this itemset (a percentage) as a double </summary>
		/// <param name="nbObject">  the number of transactions in the database where this itemset was found </param>
		/// <returns> the relative support of the itemset as a double </returns>
		public double getRelativeSupport(int nbObject)
		{
			// Divide the absolute support by the number of transactions to get the relative support
			return ((double)AbsoluteSupport()) / ((double) nbObject);
		}


		/// <summary>
		/// Check if this itemset contains a given item. </summary>
		/// <param name="item">  the item </param>
		/// <returns> true if the item is contained in this itemset </returns>
		public bool contains(int item)
		{
			for (int i = 0; i < size(); i++)
			{
				if (get(i).Equals(item))
				{
					return true;
				}
				else if (get(i) > item)
				{
					return false;
				}
			}
			return false;
		}

		/// <summary>
		/// This methods checks if another itemset is contained in this one.
		/// The method assumed that items are lexically ordered in itemsets.
		/// </summary>
		/// <param name="itemset2"> the other itemset </param>
		/// <returns> true if it is contained </returns>
		/// <summary>
		/// This methods checks if another itemset is contained in this one. </summary>
		/// <param name="itemset2"> the other itemset </param>
		/// <returns> true if it is contained </returns>
		public bool containsAll(AbstractItemset itemset2)
		{
			// first we check the size
			if (size() < itemset2.size())
			{
				return false;
			}

			// we will use this variable to remember where we are in this itemset
			int i = 0;

			// for each item in itemset2, we will try to find it in this itemset
			for (int j = 0; j < itemset2.size(); j++)
			{
				bool found = false; // flag to remember if we have find the item at position j

				// we search in this itemset starting from the current position i
				while (found == false && i < size())
				{
					// if we found the current item from itemset2, we stop searching
					if (get(i).Equals(itemset2.get(j)))
					{
						found = true;
					} // if the current item in this itemset is larger than
					// the current item from itemset2, we return false
					// because the itemsets are assumed to be lexically ordered.
					else if (get(i) > itemset2.get(j))
					{
						return false;
					}

					i++; // continue searching from position  i++
				}
				// if the item was not found in the previous loop, return false
				if (!found)
				{
					return false;
				}
			}
			return true; // if all items were found, return true
		}

		/// <summary>
		/// This method compare this itemset with another itemset to see if they are
		/// equal. The method assume that the two itemsets are lexically ordered.
		/// </summary>
		/// <returns> true or false </returns>
		public bool Equals(AbstractItemset itemset2)
		{
			// If they don't contain the same number of items, we return false
			if (this.size() != itemset2.size())
			{
				return false;
			}
			// We compare each item one by one from i to size - 1.
			for (int i = 0; i < itemset2.size(); i++)
			{
				// if different, return false
				if (!itemset2.get(i).Equals(this.get(i)))
				{
					return false;
				}
			}
			// All the items are the same, we return true.
			return true;
		}

		/// <summary>
		/// This method checks if this itemset is the same as another itemset
		/// except for the last item. </summary>
		/// <param name="itemset2"> the second itemset </param>
		/// <returns> true if they are the same except for the last item </returns>
		public  bool allTheSameExceptLastItemV2(AbstractItemset itemset2)
		{
			// if they don't contain the same number of item, return false
			if (itemset2.size() != this.size())
			{
				return false;
			}
			// Otherwise, we have to compare item by item
			for (int i = 0; i < this.size() - 1; i++)
			{
				// if they are not the last items, they should be the same
				// otherwise return false
				if (!this.get(i).Equals(itemset2.get(i)))
				{
					return false;
				}
			}
			// All items are the same. We return true.
			return true;
		}


		/// <summary>
		/// Check if the items from this itemset are all the same as those of another itemset 
		/// except the last item 
		/// and that itemset2 is lexically smaller than this itemset. If all these conditions are satisfied,
		/// this method return the last item of itemset2. Otherwise it returns null. </summary>
		/// <returns> the last item of itemset2, otherwise, null.
		///  </returns>
		public int? allTheSameExceptLastItem(AbstractItemset itemset2)
		{
			// if these itemsets do not have the same size,  return null
			if (itemset2.size() != this.size())
			{
				return null;
			}
			// We will compare all items one by one starting from position i =0 to size -1
			for (int i = 0; i < this.size(); i++)
			{
				// if this is the last position
				if (i == this.size() - 1)
				{
					// We check if the item from this itemset is be smaller (lexical order) 
					// and different from the one of itemset2.
					// If not, return null.
					if (this.get(i) >= itemset2.get(i))
					{
						return null;
					}
				}
				// If this is not the last position, we check if items are the same
				else if (!this.get(i).Equals(itemset2.get(i)))
				{
					// if not, return null
					return null;
				}
			}
			// otherwise, we return the position of the last item
			return itemset2.get(itemset2.size() - 1);
		}
	}
}